// Copyright (C) 2010, Scott W. Dunlop <swdunlop@gmail.com>
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef NOSPEX_DATA_H
#define NOSPEX_DATA_H 1

#include <features.h>
#include <stdint.h>

#define NX_DOMAIN_SIZE 100.0
#define NX_BLIP_RADIUS 4
#define NX_NODE_RADIUS 10

#define NX_TIMER_KIND   16
#define NX_INFO_KIND    32
#define NX_GRAPH_KIND   64
#define NX_ELEMENT_KIND 128
#define NX_WINDOW_KIND  256
#define NX_NODE_KIND (NX_ELEMENT_KIND | 1)
#define NX_BLIP_KIND (NX_ELEMENT_KIND | 2)
#define NX_LINK_KIND (NX_ELEMENT_KIND | 3)

#define NX_HALTED   0
#define NX_RUNNING  1
#define NX_PAUSED   2

enum {
    NX_0_EVT,                   // 0: Null event, never used.
    NX_GRAPH_CLICK_EVT,         // 1: Pointer has clicked on the graph playfield.
    NX_GRAPH_UNLINK_EVT,        // 2: Graph has been unlinked.
    NX_ELEMENT_ENTER_EVT,       // 3: Element has been entered by the pointer.
    NX_ELEMENT_LEAVE_EVT,       // 4: Element has been exited by the pointer.
    NX_ELEMENT_CLICK_EVT,       // 5: Element has been clicked by the pointer.
    NX_ELEMENT_DRAG_EVT,        // 6: Element is being dragged by the pointer.
    NX_ELEMENT_UNLINK_EVT       // 7: Element has been unlinked.
};

/** Used for millisecond-scale times throughout NoSpex. */
typedef uint64_t nx_time;

typedef void* nx_pointer;

struct nx_resource_t;
typedef struct nx_resource_t* nx_resource_p;

struct nx_element_t;
typedef struct nx_element_t* nx_element_p;

struct nx_graph_t;
typedef struct nx_graph_t* nx_graph_p;

struct nx_node_t;
typedef struct nx_node_t* nx_node_p;

struct nx_link_t;
typedef struct nx_link_t* nx_link_p;

struct nx_blip_t;
typedef struct nx_blip_t* nx_blip_p;

struct nx_info_t;
typedef struct nx_info_t* nx_info_p;

/** A header shared between the graph and its elements. */
struct nx_resource_t {
    uint32_t kind;              /** The kind of resource. */
    uint32_t use_ct;            /** The number of external references. */
    
    //---------------------------------------------------------------- Render.h
    double red;                  /** The redness of the node, in (0.0,1.0) */
    double blue;                 /** The blueness of the node, in (0.0,1.0) */
    double green;                /** The greenness of the node, in (0.0,1.0) */
};

/** An element of a NoSpex Graph, shared as a header by node, link, blip. */
struct nx_element_t {
    struct nx_resource_t rsrc;

    nx_info_p info;
    nx_element_p prev;
    nx_element_p next;
};

/** A function that is called when a NoSpex event has occurred. */
typedef void (*nx_event_fn)( 
    void* ctxt, nx_resource_p rsrc, int id, double x, double y
);

/** A collection of interconnected nodes. */
struct nx_graph_t {
    struct nx_resource_t rsrc;
    
    //------------------------------------------------------------------ Events
    nx_event_fn event_fn;      /** The event handler for this graph. */
    void*       event_cx;      /** The context for the event handler. */

    //------------------------------------------------------------------- Nodes 
    nx_node_p first_node;       /** The first node in the graph. */
    nx_node_p last_node;        /** The last node in the graph. */
   
    //------------------------------------------------------------------- Links 
    nx_link_p first_link;       /** The first link in the graph. */
    nx_link_p last_link;        /** The last link in the graph. */
   
    //------------------------------------------------------------------- Blips 
    nx_blip_p first_blip;       /** The first blip in the graph. */
    nx_blip_p last_blip;        /** The last blip in the graph. */
   
    //------------------------------------------------------------------- Stats 
    int count;                  /** The number of nodes in the graph. */
    int clock_skew;             /** Number of milliseconds drift from system.*/
    double pitch;               /** The number of pixels per unit. */
    int paused;                 /** Is the graph paused? */

    //---------------------------------------------------------------- Render.h
    int render_req;             /** Is a redraw required? */
    nx_time render_clock;       /** When was the last redraw done? */
    void* widget;               /** The display widget for this graph. */
    void* window;               /** The display window for this graph. */

    nx_element_p ptr_elem;      /** The element under the pointer. */
    nx_time ptr_down;           /** Time in ms when pointer pressed down. */
    double ptr_x;               /** Last X for the pointer. */
    double ptr_y;               /** Last X for the pointer. */

    //--------------------------------------------------------------- Physics.h
    int physics_req;            /** Status of physics update task. */
    int physics_cycles;         /** Amount of physics time left. */
    nx_time physics_clock;      /** When was the last physics done?*/
    int blips_req;              /** Status of blips update task. */
    nx_time blips_clock;        /** When was the last blips done?*/
    
    int render_timer;           /** SDL render timer id */
    int blips_timer;           /** SDL blips timer id */
};

/** A node in a connection graph. */
struct nx_node_t {
    struct nx_element_t elem;   /** Inherited fields from elem. */

    nx_graph_p graph;           /** The graph that contains this node. */
    
    double x;                    /** The X position of the node. */
    double y;                    /** The Y position of the node. */

    //--------------------------------------------------------------- Physics.h
    int ox;                     /** The cached X previous to a physics pass. */
    int oy;                     /** The cached Y previous to a physics pass. */
    double vx;                  /** The X velocity of the node. */
    double vy;                  /** The Y velocity of the node. */
};

/** A link between two nodes in a graph. */
struct nx_link_t {
    struct nx_element_t elem;   /** Inherited fields from elem. */

    nx_node_p src;              /** The origin of the link. */
    nx_node_p dst;              /** The destination of the link. */
};

/** A blip between two nodes in a graph. */
struct nx_blip_t {
    struct nx_element_t elem;   /** Inherited fields from elem. */

    nx_link_p link;             /** The link this blip travels over. */

    int origin;                 /** The origin of this blip. */
    double pitch;               /** 1.0 / duration of travel. */
    int expiry;                 /** The expiration time of the blip. */
    int defer;                  /** The time expiration was deferred. */
};

/** An annotation for a node or blip. */
struct nx_info_t {
    struct nx_resource_t rsrc;

    void* cache;
    double width, height; nx_element_p elem;
    int size;
    char data[1];               /** The text buffer for the info. */
};

/** Creates an annotation for a node or blip, tracking the node or blip.. */
nx_info_p nx_create_info( 
    nx_element_p elem,
    const char* text,
    int len
);

/** Retrieves the info associated with an element. */
nx_info_p nx_element_info( 
    nx_element_p elem
);

/** Creates a new NoSpex graph. */
nx_graph_p nx_create_graph( );

/** Determines is a graph size is viable, considering the number of nodes. */
int nx_is_viable_graph_resize( 
    nx_graph_p graph,           /** The graph to resize. */
    int width,                  /** The possible new width of the graph. */
    int height                  /** The possible new height of the graph. */
);

/** Resizes a NoSpex graph, and may request a redraw. */
void nx_resize_graph( 
    nx_graph_p graph,           /** The graph to resize. */
    int width,                  /** The new width of the graph. */
    int height                  /** The new height of the graph. */
);

/** Unlinks a NoSpex graph and all contained nodes. */
void nx_unlink_graph( 
    nx_graph_p graph            /** The graph to unlink. */
);

/** Creates a NoSpex node at a random position. */
nx_node_p nx_create_node( 
    nx_graph_p graph            /** The graph this node will belong to. */
);

/** Unlinks a NoSpex node and updates the graph. */
void nx_unlink_node( 
    nx_node_p node              /** The node to unlink. */
);

/** Creates a NoSpex link at a random position. */
nx_link_p nx_create_link( 
    nx_node_p src,
    nx_node_p dst
);

/** Unlinks a NoSpex link and updates the graph. */
void nx_unlink_link( 
    nx_link_p link              /** The link to unlink. */
);

/** Unlinks a NoSpex annotation. */
void nx_unlink_info( 
    nx_info_p info              /** The info to unlink. */
);

/** Gets the color of a NoSpex resource. */
void nx_resource_color( 
    nx_resource_p resource,
    double* red,                /** The red component, range (0.0, 1.0). */
    double* green,              /** The green component, range (0.0, 1.0). */
    double* blue                /** The blue component, range (0.0, 1.0). */
);

/** Sets the color of a NoSpex resource. */
void nx_set_resource_color( 
    nx_resource_p resource, 
    double red,                  /** The red component, range (0.0, 1.0). */
    double green,                /** The green component, range (0.0, 1.0). */
    double blue                  /** The blue component, range (0.0, 1.0). */
);

/** Sets the color of a NoSpex resource to a random color. */
void nx_set_random_resource_color(
    nx_resource_p resource              
);

/** Moves a NoSpex node to a position. */
void nx_set_node_position( 
    nx_node_p node,              /** The node to move. */
    double x,                    /** The new x position. */
    double y                     /** The new y position. */
);

/** Moves a NoSpex node to a random position. */
void nx_set_random_node_position( 
    nx_node_p node              /** The node to move. */
);

/** Prints a graph to stdout. */
void nx_print_graph(
    nx_graph_p graph            /** The graph to print. */
);

/** Prints a node to stdout. */
void nx_print_node(
    nx_node_p node              /** The node to print. */
);

/** Records the system time when the application began. */
void nx_start_system_clock( void );

/** Returns the number of milliseconds since nx_start_clock was called. */
nx_time nx_system_clock( void );

/** Returns the number of milliseconds the model has been running. */
nx_time nx_graph_clock( nx_graph_p graph );

/** Finds an element in the graph at model x, y. */
nx_element_p nx_find_element_at( nx_graph_p graph, double x, double y );

/** Converts widget coordinates into model coordinates. */
void nx_convert_to_model_xy( nx_graph_p graph, double* px, double* py );

/* Indicates a blip that originates from the link's src node. */
#define NX_FROM_SRC 101

/* Indicates a blip that originates from the link's dst node. */
#define NX_FROM_DST 202

/** Creates a new NoSpex blip. */
nx_blip_p nx_create_blip(
    nx_link_p link,             /** The link this blip travels over. */
    int origin,                 /** The origin of this blip. */
    int duration                /** The duration of travel. */
);

/** Unlinks a NoSpex blip and updates the graph. */
void nx_unlink_blip( 
    nx_blip_p blip              /** The blip to unlink. */
);

/** Unlinks a NoSpex element and all dependent elements. */
void nx_unlink_element( 
    nx_element_p element        /** The element to unlink. */
);

/** Returns the graph that contains an element. */
nx_graph_p nx_element_graph( 
    nx_element_p elem           /** The element to check. */
);

/** Increases the use counter for a resource. */
void nx_add_use( nx_resource_p resource );

/** Decreases the use counter for a resource. */
void nx_remove_use( nx_resource_p resource );

/** Increases use of Y, decreases use of X. */
void nx_change_use( nx_resource_p x, nx_resource_p y );

/** Returns the kind of resource. */
int nx_resource_kind( nx_resource_p resource );

/** Returns true if the resource is a graph. */
int nx_is_graph( nx_resource_p resource );

/** Returns true if the resource is an element. */
int nx_is_element( nx_resource_p resource );

/** Returns true if the resource is an graph. */
int nx_is_graph( nx_resource_p resource );

/** Returns non-NULL if the resource is an graph. */
nx_graph_p nx_to_graph( nx_resource_p resource );

/** Returns true if the resource is an node. */
int nx_is_node( nx_resource_p resource );

/** Returns non-NULL if the resource is an node. */
nx_node_p nx_to_node( nx_resource_p resource );

/** Returns true if the resource is an link. */
int nx_is_link( nx_resource_p resource );

/** Returns non-NULL if the resource is an link. */
nx_link_p nx_to_link( nx_resource_p resource );

/** Returns true if the resource is an blip. */
int nx_is_blip( nx_resource_p resource );

/** Returns non-NULL if the resource is an blip. */
nx_blip_p nx_to_blip( nx_resource_p resource );

/** Returns non-NULL if the resource is an element. */
nx_element_p nx_to_element( nx_resource_p resource );

/** Returns true if the resource is an info. */
int nx_is_info( nx_resource_p resource );

/** Returns non-NULL if the resource is an info. */
nx_info_p nx_to_info( nx_resource_p resource );

/** Signals the graph that a NoSpex graph event has occurred. */
void nx_signal_graph( nx_graph_p graph, int id, double x, double y );

/** Signals the graph that a NoSpex element event has occurred. */
void nx_signal_resource( nx_resource_p rsrc, int id, double x, double y );

/** Sets the graph callback. */
void nx_set_graph_callback( nx_graph_p graph, void* ctxt, nx_event_fn func );

/** Unlinks a NoSpex resource and updates the graph. */
void nx_unlink_resource( 
    nx_resource_p resource              /** The resource to unlink. */
);

/** Returns the graph associated with a resource. */
nx_graph_p nx_resource_graph( nx_resource_p resource );

/** Returns the position of a element, returns 0 if it cannot be determined.*/
int nx_element_position( nx_element_p element, double* x, double* y );

/** Records the system time when the application began. */
void nx_start_system_clock( );

/** Returns the number of milliseconds since NoSpex was started. */
nx_time nx_system_clock( );

#endif //ifndef NOSPEX_DATA_H
